#ifndef GAME_ANIMATION_GRASS_SHADER_H
#define GAME_ANIMATION_GRASS_SHADER_H
//
// Game Animation.
// Copyright (C) 2007 Department of Computer Science, University of Copenhagen
//
#include <animation/configuration.h>

#include <OpenTissue/gpu/cg/cg_program.h>
#include <OpenTissue/gpu/image/image.h>
#include <OpenTissue/gpu/image/io/image_read.h>
#include <OpenTissue/gpu/image/io/image_write.h>
#include <OpenTissue/gpu/texture/texture_texture2D.h>
#include <OpenTissue/gpu/image/image_make_noise.h>
#include <OpenTissue/gpu/image/image_alpha_modulation.h>

namespace animation
{

  /**
  * The Grass Shader.
  * This class setups (and shutdowns) the rendering before draw the geometry of the grass layer.
  *
  */
  class GrassShader
  {
  protected:

    OpenTissue::cg::Program                                m_vertex_program;
    OpenTissue::cg::Program                                m_fragment_program;

    boost::shared_ptr<OpenTissue::image::Image<unsigned char> > m_grass_image;
    OpenTissue::texture::texture2D_pointer                        m_grass_texture;

    boost::shared_ptr<OpenTissue::image::Image<unsigned char> >                 m_noise_image;
    OpenTissue::texture::texture2D_pointer m_noise_texture;
  public:

    /**
    * Pre-rendering.
    *
    * @param rightx          The x-coordinate of the camera right vector in WCS.
    * @param righty          The y-coordinate of the camera right vector in WCS.
    * @param rightz          The z-coordinate of the camera right vector in WCS.
    * @param upx             The x-coordinate of the camera up vector in WCS.
    * @param upy             The y-coordinate of the camera up vector in WCS.
    * @param upz             The z-coordinate of the camera up vector in WCS.
    * @param time            The current time, used to animate grass movement.
    * @param visible_range   Determines how far away one can see grass clumps before the fade out into the background.
    */
    void pre_render ( 
		bool reload
		, float rightx
		, float righty
		, float rightz
		, float upx
		, float upy
		, float upz
		, float time
		, float visible_range
		, float light_x,float light_y,float light_z
		, float intensity
		, float fog_density
		, float fog_color_r, float fog_color_g, float fog_color_b)
    {
      //--- Load textures if they are not allready loaded
      if(!m_grass_image)
      {
        m_grass_image.reset( new OpenTissue::image::Image<unsigned char>() );
        OpenTissue::image::read(demo_path + "TheSwampThing2008/data/grass_pack.png",*m_grass_image);

		//this code changes the alpha of the original image by multiplication.
        OpenTissue::image::Image<unsigned char> alpha(m_grass_image->width(),m_grass_image->height(), 1);
        OpenTissue::image::make_noise(alpha,128.0,255.0);
        OpenTissue::image::alpha_modulation(*m_grass_image,alpha);
        m_grass_texture = m_grass_image->create_texture(GL_RGBA);	
		
		m_noise_image.reset( new OpenTissue::image::Image<unsigned char>() );
		OpenTissue::image::read(demo_path + "TheSwampThing2008/data/cloud_noise.png",*m_noise_image);
		m_noise_texture = m_noise_image->create_texture(GL_RGBA);
		m_noise_texture->set_repeating(true);
        m_noise_texture->set_mipmapping(true);
      }

      //--- Load vertex program, note that cg-program path is currently hardcoded, a
      //--- more sensible solution would be
      //---
      //---  std::string filename = get_environment_variable("OPENTISSUE") + .... + "vp_grass.cg";
      //---
      if(!m_vertex_program.is_program_loaded()||reload)
		  if(!m_vertex_program.load_from_file(OpenTissue::cg::Program::vertex_program,demo_path + "../animation/vp_grass.cg")){
			  return;
		  }

	  m_vertex_program.set_float_param("light_vec",light_x,light_y,light_z);
	  m_vertex_program.set_float_param("intensity",intensity);

      m_vertex_program.set_float_param("right",               rightx, righty, rightz);
      m_vertex_program.set_float_param("up",                  upx,    upy,    upz);
      m_vertex_program.set_float_param("time",                time);
      m_vertex_program.set_float_param("visible_range",       visible_range);
      m_vertex_program.set_modelview_projection_matrix();
	  m_vertex_program.set_modelview_inverse_transpose();
	  m_vertex_program.set_modelview_inverse_matrix();
      //--- load fragment program
      if(!m_fragment_program.is_program_loaded()||reload)
        m_fragment_program.load_from_file(OpenTissue::cg::Program::fragment_program,demo_path + "../animation/fp_grass.cg");

      m_fragment_program.set_input_texture("texture",m_grass_texture);
      m_fragment_program.set_input_texture( "noise_texture",  m_noise_texture  );
	  m_fragment_program.set_float_param( "fog_density",  fog_density  );
	  m_fragment_program.set_float_param( "fog_color",  fog_color_r,fog_color_g,fog_color_b);

      m_fragment_program.enable();
      m_vertex_program.enable();

      //--- Setup openGL state
      glEnable(GL_MULTISAMPLE_ARB);              //--- KE 2005.10.23: Need a ge78000:-(
      glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);
      glEnable(GL_BLEND);
      glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
      glEnable(GL_ALPHA_TEST);
      glAlphaFunc(GL_GREATER, 0);
    }

    void post_render()
    {
      glDisable(GL_MULTISAMPLE_ARB);             //--- KE 2005.10.23: Need a ge78000:-(
      glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);
      glDisable(GL_ALPHA_TEST);
      glDisable(GL_BLEND);
      m_fragment_program.disable();
      m_vertex_program.disable();
    }
  };

} // namespace animation

// GAME_ANIMATION_GRASS_SHADER_H
#endif
